package com.webserver.http;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

/**
 * 服务端响应类, 将响应发送给客户端;
 * <p>
 * 负责：
 * 1.发送响应行;
 * 2.发送响应消息头;
 * 3.找到相应静态文件以响应正文的形式发送;
 */
public class HttpServletResponse {
    //声明一个Socket变量, 用于保存传入的Socket
    private Socket socket;
    //创建响应相关属性的变量
    private int statusCode = 200;
    private String statusReason = "OK";
    private File staticFile;

    /**
     * HttpServletResponse有参构造器;
     * <p>
     * 负责：将传入的socket值传入本地变量中;
     * @param socket 应该是与客户端连接的socket;
     */
    public HttpServletResponse(Socket socket) {
        //将传入的socket值赋给本地的socket(this.socket)
        this.socket = socket;
    }

    /**
     * void response(String url)方法;
     * <p>
     * 负责: 将响应发送给浏览器;
     * @throws IOException 抛出来自void PrintLine方法的IO异常,
     * 以及自身的创建流时的IO异常;
     */
    public void response() throws IOException {
        //发送响应行
        printLine("HTTP/1.1 " + statusCode + " " + statusReason);

        //发送响应消息头
        printLine("Content-Type: text/html");
        printLine("Content-Length: " + staticFile.length());
        printLine(""); //响应消息头与响应正文间有一行空行

        //发送响应消息正文
        int len;//声明一个int类型变量, 用于接收读取到的字节数据
        //创建与需要获取的静态文件的输入流
        FileInputStream fis = new FileInputStream(staticFile);
        //获取与客户端连接的输出流
        OutputStream out = socket.getOutputStream();
        //创建一个8kb的byte类型数组, 用于块读文件内的数据
        byte[] data = new byte[1024 * 8];

        //读取到内容时进入while循环
        while ((len = fis.read(data)) != -1){
            //输出读取到的有效数据, 0表示从数组下标为0开始, len表示读取多少位
            out.write(data, 0, len);
        }
    }

    /**
     * void printLine()方法;
     * <p>
     * 负责：将传入的字符串以流的形式发送给客户端的浏览器;
     * @param line 需要写出的一行;
     * @throws IOException 抛出创建于浏览器连接的字节输出流时的IO异常;
     */
    private void printLine(String line) throws IOException{
        //获取与客户端连接的输出流
        OutputStream out = socket.getOutputStream();
        /* 浏览器采用ISO_8859_1编码将字节转成字符,
         * 所以服务端要先用ISO_8859_1编码将字符转成字节
         * 再将转换好的字节发送到客户端的浏览器中
         */
        out.write(line.getBytes(StandardCharsets.ISO_8859_1));
        //结尾写出回车与换行符表示一行结束
        out.write(13);
        out.write(10);
    }

    //成员变量的get与set方法
    public int getStatusCode() {
        return statusCode;
    }

    public void setStatusCode(int statusCode) {
        this.statusCode = statusCode;
    }

    public String getStatusReason() {
        return statusReason;
    }

    public void setStatusReason(String statusReason) {
        this.statusReason = statusReason;
    }

    public File getStaticFile() {
        return staticFile;
    }

    public void setStaticFile(File staticFile) {
        this.staticFile = staticFile;
    }
}
